#!/usr/bin/env python3
# Copyright (C) 2025 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.


from collections.abc import Callable
from pathlib import Path

import pytest

from cmk.agent_based.v2 import CheckResult, Metric, Result, Service, State
from cmk.plugins.gude.agent_based import gude_relayport as gr
from cmk.plugins.gude.agent_based.gude_relayport import (
    check_gude_relayport,
    discover_gude_relayport,
    parse_gude_relayport,
)
from cmk.plugins.lib.elphase import CheckParams
from tests.unit.cmk.plugins.collection.agent_based.snmp import (
    get_parsed_snmp_section,
)

_STRING_TABLE = [
    ["TWTA 2", "1", "0", "0", "228", "4995", "0"],
    ["TWTA 3", "1", "0", "0", "190", "6000", "2"],
    ["TWTA 4", "0", "", "", "", "", ""],
]

_INPUT_TABLE = """
.1.3.6.1.2.1.1.1.0 Expert Power Control 8220-1
.1.3.6.1.2.1.1.2.0 .1.3.6.1.4.1.28507.38
.1.3.6.1.2.1.1.3.0 1638018124
.1.3.6.1.2.1.1.4.0 sysContact
.1.3.6.1.2.1.1.5.0 sysName
.1.3.6.1.2.1.1.6.0 sysLocation
.1.3.6.1.2.1.1.7.0 72
.1.3.6.1.2.1.2.1.0 1
.1.3.6.1.2.1.2.2.1.1.1 1
.1.3.6.1.2.1.2.2.1.2.1 eth_cf52259
.1.3.6.1.2.1.2.2.1.3.1 6
.1.3.6.1.2.1.2.2.1.4.1 1500
.1.3.6.1.2.1.2.2.1.5.1 100000000
.1.3.6.1.2.1.2.2.1.6.1 "00 19 32 00 9E 26 "
.1.3.6.1.2.1.2.2.1.7.1 1
.1.3.6.1.2.1.2.2.1.8.1 1
.1.3.6.1.2.1.2.2.1.9.1 1638018124
.1.3.6.1.2.1.2.2.1.10.1 122573894
.1.3.6.1.2.1.2.2.1.11.1 36753912
.1.3.6.1.2.1.2.2.1.12.1 523889056
.1.3.6.1.2.1.2.2.1.13.1 0
.1.3.6.1.2.1.2.2.1.14.1 185
.1.3.6.1.2.1.2.2.1.15.1 0
.1.3.6.1.2.1.2.2.1.16.1 2133919626
.1.3.6.1.2.1.2.2.1.17.1 10128255
.1.3.6.1.2.1.2.2.1.18.1 10838295
.1.3.6.1.2.1.2.2.1.19.1 0
.1.3.6.1.2.1.2.2.1.20.1 10128255
.1.3.6.1.2.1.2.2.1.21.1 0
.1.3.6.1.2.1.2.2.1.22.1 .0.0
.1.3.6.1.4.1.28507.38.1.1.1.1.0 2
.1.3.6.1.4.1.28507.38.1.1.1.2.1.2.1 172.240.17.75
.1.3.6.1.4.1.28507.38.1.1.1.2.1.2.2
.1.3.6.1.4.1.28507.38.1.1.1.2.1.2.3
.1.3.6.1.4.1.28507.38.1.1.1.2.1.2.4
.1.3.6.1.4.1.28507.38.1.1.1.2.1.2.5
.1.3.6.1.4.1.28507.38.1.1.1.2.1.2.6
.1.3.6.1.4.1.28507.38.1.1.1.2.1.2.7
.1.3.6.1.4.1.28507.38.1.1.1.2.1.2.8
.1.3.6.1.4.1.28507.38.1.3.1.1.0 12
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.1 Power Port A1
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.2 Power Port A2
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.3 Power Port A3
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.4 Power Port A4
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.5 Power Port A5
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.6 Power Port A6
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.7 Power Port B1
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.8 Power Port B2
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.9 Power Port B3
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.10 Power Port B4
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.11 Power Port B5
.1.3.6.1.4.1.28507.38.1.3.1.2.1.2.12 Power Port B6
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.1 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.2 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.3 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.4 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.5 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.6 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.7 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.8 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.9 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.10 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.11 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.3.12 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.1 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.2 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.3 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.4 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.5 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.6 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.7 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.8 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.9 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.10 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.11 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.4.12 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.1 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.2 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.3 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.4 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.5 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.6 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.7 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.8 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.9 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.10 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.11 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.5.12 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.1 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.2 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.3 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.4 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.5 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.6 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.7 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.8 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.9 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.10 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.11 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.6.12 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.1 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.2 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.3 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.4 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.5 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.6 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.7 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.8 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.9 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.10 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.11 0
.1.3.6.1.4.1.28507.38.1.3.1.2.1.7.12 0
.1.3.6.1.4.1.28507.38.1.3.10.0 0
.1.3.6.1.4.1.28507.38.1.5.1.1.0 2
.1.3.6.1.4.1.28507.38.1.5.1.2.1.2.1 1
.1.3.6.1.4.1.28507.38.1.5.1.2.1.2.2 1
.1.3.6.1.4.1.28507.38.1.5.1.2.1.3.1 454
.1.3.6.1.4.1.28507.38.1.5.1.2.1.3.2 279
.1.3.6.1.4.1.28507.38.1.5.1.2.1.4.1 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.4.2 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.5.1 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.5.2 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.6.1 231
.1.3.6.1.4.1.28507.38.1.5.1.2.1.6.2 231
.1.3.6.1.4.1.28507.38.1.5.1.2.1.7.1 4997
.1.3.6.1.4.1.28507.38.1.5.1.2.1.7.2 4997
.1.3.6.1.4.1.28507.38.1.5.1.2.1.8.1 62
.1.3.6.1.4.1.28507.38.1.5.1.2.1.8.2 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.9.1 -1084
.1.3.6.1.4.1.28507.38.1.5.1.2.1.9.2 581
.1.3.6.1.4.1.28507.38.1.5.1.2.1.10.1 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.10.2 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.11.1 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.11.2 -1
.1.3.6.1.4.1.28507.38.1.5.1.2.1.12.1 627
.1.3.6.1.4.1.28507.38.1.5.1.2.1.12.2 794
.1.3.6.1.4.1.28507.38.1.5.1.2.1.13.1 454
.1.3.6.1.4.1.28507.38.1.5.1.2.1.13.2 279
.1.3.6.1.4.1.28507.38.1.5.1.2.1.14.1 627
.1.3.6.1.4.1.28507.38.1.5.1.2.1.14.2 794
.1.3.6.1.4.1.28507.38.1.5.1.2.1.15.1 274079602
.1.3.6.1.4.1.28507.38.1.5.1.2.1.15.2 274078939
.1.3.6.1.4.1.28507.38.1.5.1.2.1.16.1 454
.1.3.6.1.4.1.28507.38.1.5.1.2.1.16.2 279
.1.3.6.1.4.1.28507.38.1.5.1.2.1.17.1 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.17.2 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.18.1 454
.1.3.6.1.4.1.28507.38.1.5.1.2.1.18.2 279
.1.3.6.1.4.1.28507.38.1.5.1.2.1.19.1 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.19.2 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.20.1 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.20.2 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.21.1 165
.1.3.6.1.4.1.28507.38.1.5.1.2.1.21.2 773
.1.3.6.1.4.1.28507.38.1.5.1.2.1.22.1 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.22.2 0
.1.3.6.1.4.1.28507.38.1.5.1.2.1.23.1 165
.1.3.6.1.4.1.28507.38.1.5.1.2.1.23.2 773
.1.3.6.1.4.1.28507.38.1.5.2.1.2.1 1
.1.3.6.1.4.1.28507.38.1.5.2.1.2.2 1
.1.3.6.1.4.1.28507.38.1.5.5.1.0 0
.1.3.6.1.4.1.28507.38.1.6.1.1.2.1 235
"""


def test_discovery_function() -> None:
    assert list(discover_gude_relayport(parse_gude_relayport(_STRING_TABLE))) == [
        Service(item="TWTA 2"),
        Service(item="TWTA 3"),
        Service(item="TWTA 4"),
    ]


@pytest.mark.parametrize(
    "item, params, expected",
    [
        pytest.param(
            "not_found",
            {
                "voltage": (220, 210),
                "current": (15, 16),
            },
            [],
            id="Item not found",
        ),
        pytest.param(
            "TWTA 2",
            {
                "voltage": (220, 210),
                "current": (15, 16),
            },
            [
                Result(state=State.OK, summary="Device status: on(0)"),
                Result(state=State.OK, summary="Voltage: 228.0 V"),
                Metric("voltage", 228.0),
                Result(state=State.OK, summary="Current: 0.0 A"),
                Metric("current", 0.0, levels=(15.0, 16.0)),
                Result(state=State.OK, summary="Power: 0.0 W"),
                Metric("power", 0.0),
                Result(state=State.OK, summary="Apparent Power: 0.0 VA"),
                Metric("appower", 0.0),
                Result(state=State.OK, summary="Frequency: 50.0 hz"),
                Metric("frequency", 49.95),
            ],
            id="Everything is OK",
        ),
        pytest.param(
            "TWTA 3",
            {
                "voltage": (220, 210),
                "current": (15, 16),
            },
            [
                Result(state=State.OK, summary="Device status: on(0)"),
                Result(
                    state=State.CRIT, summary="Voltage: 190.0 V (warn/crit below 220.0 V/210.0 V)"
                ),
                Metric("voltage", 190.0),
                Result(state=State.OK, summary="Current: 0.0 A"),
                Metric("current", 0.0, levels=(15.0, 16.0)),
                Result(state=State.OK, summary="Power: 0.0 W"),
                Metric("power", 0.0),
                Result(state=State.OK, summary="Apparent Power: 2.0 VA"),
                Metric("appower", 2.0),
                Result(state=State.OK, summary="Frequency: 60.0 hz"),
                Metric("frequency", 60.0),
            ],
            id="Voltage too low. CRIT State",
        ),
        pytest.param(
            "TWTA 4",
            {
                "voltage": (220, 210),
                "current": (15, 16),
            },
            [Result(state=State.CRIT, summary="Device status: off(2)")],
            id="Voltage too low",
        ),
    ],
)
def test_check_function(
    item: str,
    params: CheckParams,
    expected: CheckResult,
) -> None:
    assert list(check_gude_relayport(item, params, parse_gude_relayport(_STRING_TABLE))) == expected


def test_not_having_data_does_not_crash_parsing(as_path: Callable[[str], Path]) -> None:
    snmp_walk = as_path(_INPUT_TABLE)
    parsed_section = get_parsed_snmp_section(gr.snmp_section_gude_relayport, snmp_walk)
    assert parsed_section
    result = list(gr.check_gude_relayport("Power Port A2", {}, parsed_section))
    assert result == [Result(state=State.CRIT, summary="Device status: off(2)")]
